package  hhq.demo.webchart;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.alibaba.fastjson.JSONObject;

import org.springframework.stereotype.Component;


@ServerEndpoint( "/webchart/{userId}")
@Component
public class WebSocketServer {

    /** 静态变量，全局，用来记录当前在线连接数。应该把它设计成线程安全的。 */
    private static int onlineCount = 0;
    /** concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。 */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    final static int BUF_SIZE = 1024 * 1024 * 20;


    // 私有，一个连接一个
    /** 与某个客户端的连接会话，需要通过它来给客户端发送数据 */
    private Session session;
    /** 接收userId */
    private String userId = "";
    private String userName = "";
    private WebSocketServer conn_ed = null; // 已经建立起来的连接
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        session.setMaxTextMessageBufferSize(BUF_SIZE);
        session.setMaxBinaryMessageBufferSize(BUF_SIZE);
        //System.out.println("opening websocket");
        this.session = session;
        this.userId = userId;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
            // 加入set中
        } else {
            webSocketMap.put(userId, this);
            // 加入set中
            addOnlineCount();
            // 在线数加1
        }
        System.out.println("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
        send_All_list();
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            // 从set中删除
            subOnlineCount();
        }
        //System.out.println("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
        this.send_All_list();
    }

    // 处理字符串，例如json
    @OnMessage
    public void onMessage(String mess, Session session){
        JSONObject json=JSONObject.parseObject(mess);
        System.out.println("onMessage:" + json.getString("op"));
        switch(json.getString("op")){
            case "rename":
                this.userName=json.getString("name");
                this.send_All_list();
                break;
            case "conn":  // 请求与某个用户建立连接
                if(webSocketMap.containsKey(json.getString("want"))){
                    WebSocketServer ws=webSocketMap.get(json.getString("want"));
                    JSONObject resp = new JSONObject();
                    resp.put("op", "conn_resp");
                    if(json.getString("want").equals(this.userId)){
                        resp.put("res", "self"); //  不能自己连接自己
                    }
                    else if(ws.conn_ed == null){  // 如果对方没有建立连接
                        this.conn_ed = ws;   // 我发的变成对方
                        ws.conn_ed = this;  // 对方变成我方
                        resp.put("res", "succ");
                        JSONObject js=new JSONObject() ; // 宣告对方你已经被建立连接
                        js.put("op", "ask"); 
                        js.put("uid", this.userId);
                        try {
                            ws.session.getBasicRemote().sendText(js.toJSONString());
                        } catch (IOException e) {
                            e.printStackTrace();
                            resp.put("res", "fail");
                        }
                    }else{  // 对方已经建立连接
                        resp.put("res", "fail");
                    }
                    try {
                        this.session.getBasicRemote().sendText(resp.toJSONString());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case "disconn": //宣布断开与用户的连接
                if(conn_ed != null){
                    conn_ed.disConnection();
                    conn_ed = null;
                }
                break;
            case "list": // 请求获取当前用户在线列表
                break;
            case "ping": // 心跳
                try {
                    this.session.getBasicRemote().sendText("pong");
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    void disConnection(){ // 宣布结束连接
        JSONObject json=new JSONObject();
        json.put("op", "disconn");
        this.conn_ed = null;
        try {
            this.session.getBasicRemote().sendText(json.toJSONString());
        } catch (IOException e) {
            System.err.println("dis Connection error");
        }
    }

    /**
     * 处理字节流byte[]信息
     */
    @OnMessage
    public void onMessage(byte[] arr, Session session) {
        if ( arr==null || arr.length == 0)
            return ;
        try {
            if(conn_ed != null){
                conn_ed.sendMessage(arr);
            }else{
                this.disConnection();
            }
        } catch (Exception e) {
            this.disConnection();
        }
    }
    /**
     * 
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(byte[] message) throws IOException {
        this.session.getBasicRemote().sendBinary(ByteBuffer.wrap(message));
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    // private static synchronized String[] getAllList(){
    //     List<String> userList = new LinkedList<>();
    //     for(String key: webSocketMap.keySet()){
    //         userList.add(key);
    //     }
    //     String[] res = new String[userList.size()];
    //     userList.toArray(res);
    //     return res;
    // }

    private synchronized void send_All_list(){
        List<String> ids = new LinkedList<>();
        List<String> names = new LinkedList<>();
        Set<Entry<String, WebSocketServer>> ens = webSocketMap.entrySet();
        for(Entry<String, WebSocketServer> en: ens){
            ids.add(en.getKey());
            names.add(en.getValue().userName);
        }
        String[] res_id = new String[ids.size()];
        String[] res_name = new String[ids.size()];
        ids.toArray(res_id);
        names.toArray(res_name);
        JSONObject json=new JSONObject();
        json.put("ids", res_id);
        json.put("names", res_name);
        json.put("op", "list");
        String txt = json.toJSONString();
        try {
            for(WebSocketServer ws: webSocketMap.values()){
                // if( ws==this)  // 如果不发给自己
                //     continue;
                ws.session.getBasicRemote().sendText(txt);
            }
            //System.out.println("发送所有列表成功");
        } catch (IOException e) {
            System.err.println("send_All_list() error");
        }
    }
}